பைத்தானின் இட்டரேஷன் சக்தியை வெளிக்கொணருங்கள். __iter__ மற்றும் __next__ மெத்தட்களைப் பயன்படுத்தி தனிப்பயன் இட்டரேட்டர்களை உருவாக்குவதற்கான ஒரு விரிவான வழிகாட்டி.
பைத்தானின் இட்டரேட்டர் புரோட்டோகால்: __iter__ மற்றும் __next__ ஒரு ஆழமான பார்வை
புரோகிராமிங்கில் இட்டரேஷன் என்பது மிகவும் அடிப்படையான கருத்துக்களில் ஒன்றாகும். பைத்தானில், இது எளிமையான for லூப்கள் முதல் சிக்கலான தரவு செயலாக்க பைப்லைன்கள் வரை அனைத்தையும் இயக்கும் நேர்த்தியான மற்றும் திறமையான ஒரு பொறிமுறையாகும். நீங்கள் ஒரு லிஸ்ட்டை லூப் செய்யும்போது, ஒரு கோப்பிலிருந்து வரிகளைப் படிக்கும்போது, அல்லது தரவுத்தள முடிவுகளுடன் பணிபுரியும்போது இதை ஒவ்வொரு நாளும் பயன்படுத்துகிறீர்கள். ஆனால் இதன் பின்னணியில் என்ன நடக்கிறது என்று நீங்கள் எப்போதாவது யோசித்ததுண்டா? பைத்தான் எப்படி இத்தனை வெவ்வேறு வகையான ஆப்ஜெக்ட்களிலிருந்து 'அடுத்த' உருப்படியை பெறுவது என்று தெரிந்துகொள்கிறது?
இதற்கான பதில், இட்டரேட்டர் புரோட்டோகால் எனப்படும் ஒரு சக்திவாய்ந்த மற்றும் நேர்த்தியான வடிவமைப்பு வடிவத்தில் உள்ளது. இந்த புரோட்டோகால் தான் பைத்தானின் வரிசை போன்ற அனைத்து ஆப்ஜெக்ட்களும் பேசும் பொதுவான மொழியாகும். இந்த புரோட்டோகாலைப் புரிந்துகொண்டு செயல்படுத்துவதன் மூலம், பைத்தானின் இட்டரேஷன் கருவிகளுடன் முழுமையாக இணக்கமான உங்கள் சொந்த தனிப்பயன் ஆப்ஜெக்ட்களை உருவாக்கலாம், இது உங்கள் குறியீட்டை மேலும் வெளிப்படையானதாகவும், நினைவக-திறனுள்ளதாகவும், மேலும் 'பைத்தானிக்' ஆகவும் மாற்றும்.
இந்த விரிவான வழிகாட்டி உங்களை இட்டரேட்டர் புரோட்டோகாலின் ஆழமான பார்வைக்கு அழைத்துச் செல்லும். நாங்கள் `__iter__` மற்றும் `__next__` மெத்தட்களின் பின்னணியில் உள்ள மாயத்தை வெளிக்கொணர்வதுடன், ஒரு இட்டரபிள் மற்றும் இட்டரேட்டருக்கு இடையிலான முக்கியமான வித்தியாசத்தை தெளிவுபடுத்துவோம், மேலும் உங்கள் சொந்த தனிப்பயன் இட்டரேட்டர்களை புதிதாக உருவாக்குவது எப்படி என்று படிப்படியாக உங்களுக்கு வழிகாட்டுவோம். நீங்கள் பைத்தானின் உள் செயல்பாடுகளைப் பற்றிய உங்கள் புரிதலை ஆழப்படுத்த விரும்பும் ஒரு இடைநிலை டெவலப்பராக இருந்தாலும் சரி, அல்லது மேலும் அதிநவீன API-களை வடிவமைப்பதை நோக்கமாகக் கொண்ட ஒரு நிபுணராக இருந்தாலும் சரி, இட்டரேட்டர் புரோட்டோகாலில் தேர்ச்சி பெறுவது உங்கள் பயணத்தில் ஒரு முக்கியமான படியாகும்.
'ஏன்': இட்டரேஷனின் முக்கியத்துவமும் சக்தியும்
தொழில்நுட்ப செயலாக்கத்தில் நாம் மூழ்குவதற்கு முன், இட்டரேட்டர் புரோட்டோகால் ஏன் மிகவும் முக்கியமானது என்பதைப் பாராட்டுவது அவசியம். அதன் நன்மைகள் வெறும் `for` லூப்களை இயக்குவதையும் தாண்டிச் செல்கின்றன.
நினைவகத் திறன் மற்றும் சோம்பேறி மதிப்பீடு (Lazy Evaluation)
நீங்கள் பல ஜிகாபைட் அளவுள்ள ஒரு பெரிய பதிவு கோப்பை (log file) செயலாக்க வேண்டும் என்று கற்பனை செய்து பாருங்கள். நீங்கள் முழு கோப்பையும் நினைவகத்தில் ஒரு லிஸ்ட்டாகப் படித்தால், உங்கள் கணினியின் வளங்கள் தீர்ந்துவிடும். இட்டரேட்டர்கள் இந்த சிக்கலை சோம்பேறி மதிப்பீடு (lazy evaluation) எனப்படும் ஒரு கருத்தின் மூலம் அழகாக தீர்க்கின்றன.
ஒரு இட்டரேட்டர் எல்லா தரவையும் ஒரே நேரத்தில் ஏற்றாது. அதற்கு பதிலாக, அது கேட்கப்படும்போது மட்டுமே, ஒரு நேரத்தில் ஒரு உருப்படியை உருவாக்குகிறது அல்லது பெறுகிறது. அது வரிசையில் எங்கே இருக்கிறது என்பதை நினைவில் கொள்ள ஒரு உள் நிலையை பராமரிக்கிறது. இதன் பொருள், நீங்கள் மிகக் குறைந்த, நிலையான அளவு நினைவகத்துடன் (கோட்பாட்டளவில்) எல்லையற்ற பெரிய தரவு ஓட்டத்தை செயலாக்க முடியும். உங்கள் நிரலை செயலிழக்கச் செய்யாமல் ஒரு பெரிய கோப்பை வரி வரியாகப் படிக்க அனுமதிக்கும் அதே கொள்கை இதுதான்.
சுத்தமான, படிக்கக்கூடிய மற்றும் உலகளாவிய குறியீடு
இட்டரேட்டர் புரோட்டோகால் வரிசைமுறை அணுகலுக்கு ஒரு உலகளாவிய இடைமுகத்தை வழங்குகிறது. லிஸ்ட்கள், டூபிள்கள், அகராதிகள், சரங்கள், கோப்பு ஆப்ஜெக்ட்கள் மற்றும் பல வகைகள் இந்த புரோட்டோகாலைக் கடைப்பிடிப்பதால், அவை அனைத்தையும் கையாள நீங்கள் ஒரே தொடரியலைப் பயன்படுத்தலாம்—அதாவது `for` லூப். இந்த единообразие பைத்தானின் வாசிப்புத்தன்மைக்கு ஒரு மூலக்கல்லாகும்.
இந்த குறியீட்டைக் கவனியுங்கள்:
குறியீடு:
my_list = [1, 2, 3]
for item in my_list:
print(item)
my_string = "abc"
for char in my_string:
print(char)
with open('my_file.txt', 'r') as f:
for line in f:
print(line)
`for` லூப் ஒரு முழு எண்களின் லிஸ்ட், எழுத்துக்களின் சரம், அல்லது ஒரு கோப்பின் வரிகள் மீது இட்டரேட் செய்கிறதா என்பதைப் பற்றி கவலைப்படுவதில்லை. அது வெறுமனே ஆப்ஜெக்டிடம் அதன் இட்டரேட்டரைக் கேட்கிறது, பின்னர் அந்த இட்டரேட்டரிடம் அதன் அடுத்த உருப்படியைத் திரும்பத் திரும்பக் கேட்கிறது. இந்த சுருக்கம் நம்பமுடியாத அளவிற்கு சக்தி வாய்ந்தது.
இட்டரேட்டர் புரோட்டோகாலை பிரித்தாய்தல்
இந்த புரோட்டோகால் ஆச்சரியப்படும் வகையில் எளிமையானது, இது இரண்டு சிறப்பு மெத்தட்களால் மட்டுமே வரையறுக்கப்படுகிறது, அவை பெரும்பாலும் "டண்டர்" (இரட்டை அடிக்கோடு) மெத்தட்கள் என்று அழைக்கப்படுகின்றன:
- `__iter__()`
- `__next__()`
இவற்றை முழுமையாகப் புரிந்துகொள்ள, நாம் முதலில் தொடர்புடைய ஆனால் வேறுபட்ட இரண்டு கருத்துக்களுக்கு இடையிலான வேறுபாட்டைப் புரிந்து கொள்ள வேண்டும்: ஒரு இட்டரபிள் மற்றும் ஒரு இட்டரேட்டர்.
இட்டரபிள் மற்றும் இட்டரேட்டர்: ஒரு முக்கியமான வேறுபாடு
இது பெரும்பாலும் புதியவர்களுக்கு குழப்பத்தை ஏற்படுத்தும் ஒரு விஷயம், ஆனால் இந்த வேறுபாடு மிக முக்கியமானது.
இட்டரபிள் என்றால் என்ன?
ஒரு இட்டரபிள் என்பது லூப் செய்யக்கூடிய எந்தவொரு ஆப்ஜெக்ட்டும் ஆகும். இது ஒரு இட்டரேட்டரைப் பெற உள்ளமைக்கப்பட்ட `iter()` செயல்பாட்டிற்கு நீங்கள் அனுப்பக்கூடிய ஒரு ஆப்ஜெக்ட் ஆகும். தொழில்நுட்ப ரீதியாக, ஒரு ஆப்ஜெக்ட் `__iter__` மெத்தடைச் செயல்படுத்தினால் அது இட்டரபிளாகக் கருதப்படுகிறது. அதன் `__iter__` மெத்தடின் ஒரே நோக்கம் ஒரு இட்டரேட்டர் ஆப்ஜெக்டைத் திருப்பித் தருவதாகும்.
உள்ளமைக்கப்பட்ட இட்டரபிள்களின் எடுத்துக்காட்டுகள்:
- லிஸ்ட்கள் (`[1, 2, 3]`)
- டூபிள்கள் (`(1, 2, 3)`)
- சரங்கள் (`"hello"`)
- அகராதிகள் (`{'a': 1, 'b': 2}` - கீ-கள் மீது இட்டரேட் செய்கிறது)
- செட்கள் (`{1, 2, 3}`)
- கோப்பு ஆப்ஜெக்ட்கள்
நீங்கள் ஒரு இட்டரபிளை ஒரு கொள்கலன் அல்லது தரவின் மூலமாக நினைக்கலாம். அது உருப்படிகளை எப்படி உருவாக்குவது என்று தானாக அறியாது, ஆனால் அதைச் செய்யக்கூடிய ஒரு ஆப்ஜெக்டை எப்படி உருவாக்குவது என்று அதற்குத் தெரியும்: அதுதான் இட்டரேட்டர்.
இட்டரேட்டர் என்றால் என்ன?
ஒரு இட்டரேட்டர் என்பது இட்டரேஷனின் போது மதிப்புகளை உருவாக்கும் வேலையைச் செய்யும் ஆப்ஜெக்ட் ஆகும். இது ஒரு தரவு ஓட்டத்தைக் குறிக்கிறது. ஒரு இட்டரேட்டர் இரண்டு மெத்தட்களைச் செயல்படுத்த வேண்டும்:
- `__iter__()`: இந்த மெத்தட் இட்டரேட்டர் ஆப்ஜெக்டையே (`self`) திருப்பித் தர வேண்டும். இது இட்டரேட்டர்களும் இட்டரபிள்கள் எதிர்பார்க்கப்படும் இடங்களில், உதாரணமாக, ஒரு `for` லூப்பில் பயன்படுத்தப்படுவதை உறுதி செய்யத் தேவைப்படுகிறது.
- `__next__()`: இந்த மெத்தட் இட்டரேட்டரின் இயந்திரம் ஆகும். இது வரிசையில் அடுத்த உருப்படியைத் திருப்பித் தருகிறது. திருப்பித் தர மேலும் உருப்படிகள் இல்லாதபோது, அது கட்டாயம் `StopIteration` விதிவிலக்கை எழுப்ப வேண்டும். இந்த விதிவிலக்கு ஒரு பிழை அல்ல; இது இட்டரேஷன் முடிந்துவிட்டது என்று லூப்பிங் அமைப்புக்கு அனுப்பப்படும் ஒரு நிலையான சமிக்ஞையாகும்.
ஒரு இட்டரேட்டரின் முக்கிய பண்புகள்:
- இது நிலையை பராமரிக்கிறது: ஒரு இட்டரேட்டர் வரிசையில் அதன் தற்போதைய நிலையை நினைவில் வைத்திருக்கும்.
- இது ஒரு நேரத்தில் ஒரு மதிப்பை உருவாக்குகிறது: `__next__` மெத்தட் வழியாக.
- இது தீர்ந்துவிடக்கூடியது: ஒரு இட்டரேட்டர் முழுமையாகப் பயன்படுத்தப்பட்டவுடன் (அதாவது, அது `StopIteration` ஐ எழுப்பியவுடன்), அது காலியாகிவிடும். நீங்கள் அதை மீட்டமைக்கவோ அல்லது மீண்டும் பயன்படுத்தவோ முடியாது. மீண்டும் இட்டரேட் செய்ய, நீங்கள் அசல் இட்டரபிளுக்குச் சென்று அதில் மீண்டும் `iter()` ஐ அழைப்பதன் மூலம் ஒரு புதிய இட்டரேட்டரைப் பெற வேண்டும்.
நமது முதல் தனிப்பயன் இட்டரேட்டரை உருவாக்குதல்: ஒரு படிப்படியான வழிகாட்டி
கோட்பாடு சிறந்தது, ஆனால் புரோட்டோகாலைப் புரிந்துகொள்வதற்கான சிறந்த வழி அதை நீங்களே உருவாக்குவதுதான். ஒரு தொடக்க எண்ணிலிருந்து ஒரு வரம்பு வரை இட்டரேட் செய்யும் ஒரு கவுண்டராக செயல்படும் ஒரு எளிய கிளாஸை உருவாக்குவோம்.
எடுத்துக்காட்டு 1: ஒரு எளிய கவுண்டர் கிளாஸ்
நாம் `CountUpTo` என்ற ஒரு கிளாஸை உருவாக்குவோம். நீங்கள் அதன் ஒரு இன்ஸ்டன்ஸை உருவாக்கும்போது, நீங்கள் ஒரு அதிகபட்ச எண்ணைக் குறிப்பிடுவீர்கள், மேலும் நீங்கள் அதை இட்டரேட் செய்யும்போது, அது 1 முதல் அந்த அதிகபட்ச எண் வரையிலான எண்களை வழங்கும்.
குறியீடு:
class CountUpTo:
"""குறிப்பிட்ட அதிகபட்ச எண் வரை 1-லிருந்து எண்ணும் ஒரு இட்டரேட்டர்."""
def __init__(self, max_num):
print("CountUpTo ஆப்ஜெக்டை துவக்குகிறது...")
self.max_num = max_num
self.current = 0 # இது நிலையை சேமிக்கும்
def __iter__(self):
print("__iter__ அழைக்கப்பட்டது, self-ஐ திருப்புகிறது...")
# இந்த ஆப்ஜெக்ட் அதன் சொந்த இட்டரேட்டர், எனவே நாம் self-ஐ திருப்புகிறோம்
return self
def __next__(self):
print("__next__ அழைக்கப்பட்டது...")
if self.current < self.max_num:
self.current += 1
return self.current
else:
# இது முக்கியமான பகுதி: நாம் முடித்துவிட்டோம் என்று சிக்னல் செய்யவும்.
print("Raising StopIteration.")
raise StopIteration
# இதை எப்படி பயன்படுத்துவது
print("கவுண்டர் ஆப்ஜெக்டை உருவாக்குகிறது...")
counter = CountUpTo(3)
print("\nfor லூப்பைத் தொடங்குகிறது...")
for number in counter:
print(f"for லூப் பெற்றது: {number}")
குறியீடு பிரிப்பு மற்றும் விளக்கம்
`for` லூப் இயங்கும்போது என்ன நடக்கிறது என்பதைப் பகுப்பாய்வு செய்வோம்:
- துவக்கம்: `counter = CountUpTo(3)` என்பது நமது கிளாஸின் ஒரு இன்ஸ்டன்ஸை உருவாக்குகிறது. `__init__` மெத்தட் இயங்கி, `self.max_num`-ஐ 3 ஆகவும் `self.current`-ஐ 0 ஆகவும் அமைக்கிறது. நமது ஆப்ஜெக்டின் நிலை இப்போது துவக்கப்பட்டுள்ளது.
- லூப்பைத் தொடங்குதல்: `for number in counter:` வரி எட்டப்பட்டதும், பைத்தான் உள்நாட்டில் `iter(counter)` ஐ அழைக்கிறது.
- `__iter__` அழைக்கப்படுகிறது: `iter(counter)` அழைப்பு நமது `counter.__iter__()` மெத்தடைத் தூண்டுகிறது. நமது குறியீட்டிலிருந்து நீங்கள் பார்க்கிறபடி, இந்த மெத்தட் வெறுமனே ஒரு செய்தியை அச்சிட்டு `self` ஐத் திருப்பித் தருகிறது. இது `for` லூப்பிற்கு, 'நீங்கள் `__next__` ஐ அழைக்க வேண்டிய ஆப்ஜெக்ட் நானே!' என்று சொல்கிறது.
- லூப் தொடங்குகிறது: இப்போது `for` லூப் தயாராக உள்ளது. ஒவ்வொரு இட்டரேஷனிலும், அது பெற்ற இட்டரேட்டர் ஆப்ஜெக்ட்டில் (அது நமது `counter` ஆப்ஜெக்ட்) `next()` ஐ அழைக்கும்.
- முதல் `__next__` அழைப்பு: `counter.__next__()` மெத்தட் அழைக்கப்படுகிறது. `self.current` 0 ஆகும், இது `self.max_num` (3) ஐ விடக் குறைவு. குறியீடு `self.current`-ஐ 1 ஆக அதிகரித்து அதைத் திருப்பித் தருகிறது. `for` லூப் இந்த மதிப்பை `number` மாறிக்கு ஒதுக்குகிறது, மற்றும் லூப் பாடி (`print(...)`) செயல்படுத்தப்படுகிறது.
- இரண்டாவது `__next__` அழைப்பு: லூப் தொடர்கிறது. `__next__` மீண்டும் அழைக்கப்படுகிறது. `self.current` 1 ஆக உள்ளது. அது 2 ஆக அதிகரிக்கப்பட்டு திருப்பித் தரப்படுகிறது.
- மூன்றாவது `__next__` அழைப்பு: `__next__` மீண்டும் அழைக்கப்படுகிறது. `self.current` 2 ஆக உள்ளது. அது 3 ஆக அதிகரிக்கப்பட்டு திருப்பித் தரப்படுகிறது.
- இறுதி `__next__` அழைப்பு: `__next__` மீண்டும் ஒரு முறை அழைக்கப்படுகிறது. இப்போது, `self.current` 3 ஆக உள்ளது. `self.current < self.max_num` என்ற நிபந்தனை தவறானது. `else` பிளாக் செயல்படுத்தப்பட்டு, `StopIteration` எழுப்பப்படுகிறது.
- லூப்பை முடித்தல்: `for` லூப் `StopIteration` விதிவிலக்கைப் பிடிப்பதற்காக வடிவமைக்கப்பட்டுள்ளது. அது அவ்வாறு செய்யும்போது, இட்டரேஷன் முடிந்துவிட்டது என்பதை அறிந்து, அது அழகாக முடிவடைகிறது. நிரல் லூப்பிற்குப் பிறகு உள்ள எந்த குறியீட்டையும் தொடர்ந்து செயல்படுத்துகிறது.
ஒரு முக்கிய விவரத்தைக் கவனியுங்கள்: நீங்கள் அதே `counter` ஆப்ஜெக்ட்டில் மீண்டும் `for` லூப்பை இயக்க முயற்சித்தால், அது வேலை செய்யாது. இட்டரேட்டர் தீர்ந்துவிட்டது. `self.current` ஏற்கனவே 3 ஆக உள்ளது, எனவே `__next__` க்கு எந்தவொரு அடுத்தடுத்த அழைப்பும் உடனடியாக `StopIteration`-ஐ எழுப்பும். இது நமது ஆப்ஜெக்ட்டை அதன் சொந்த இட்டரேட்டராகக் கொண்டிருப்பதன் விளைவாகும்.
மேம்பட்ட இட்டரேட்டர் கருத்துக்கள் மற்றும் நிஜ-உலக பயன்பாடுகள்
எளிய கவுண்டர்கள் கற்றுக்கொள்ள ஒரு சிறந்த வழி, ஆனால் இட்டரேட்டர் புரோட்டோகாலின் உண்மையான சக்தி மேலும் சிக்கலான, தனிப்பயன் தரவு கட்டமைப்புகளுக்குப் பயன்படுத்தப்படும்போது பிரகாசிக்கிறது.
இட்டரபிள் மற்றும் இட்டரேட்டரை இணைப்பதில் உள்ள சிக்கல்
நமது `CountUpTo` எடுத்துக்காட்டில், கிளாஸ் இட்டரபிள் மற்றும் இட்டரேட்டர் இரண்டாகவும் இருந்தது. இது எளிமையானது ஆனால் ஒரு பெரிய குறைபாட்டைக் கொண்டுள்ளது: இதன் விளைவாக வரும் இட்டரேட்டர் தீர்ந்துவிடக்கூடியது. நீங்கள் ஒரு முறை அதன் மீது லூப் செய்தவுடன், அது முடிந்துவிட்டது.
குறியீடு:
counter = CountUpTo(2)
print("முதல் இட்டரேஷன்:")
for num in counter: print(num) # நன்றாக வேலை செய்கிறது
print("\nஇரண்டாவது இட்டரேஷன்:")
for num in counter: print(num) # எதையும் அச்சிடவில்லை!
இது நிகழ்கிறது ஏனெனில் நிலை (`self.current`) ஆப்ஜெக்ட்டிலேயே சேமிக்கப்படுகிறது. முதல் லூப்பிற்குப் பிறகு, `self.current` 2 ஆக உள்ளது, மேலும் எந்தவொரு அடுத்த `__next__` அழைப்புகளும் `StopIteration`-ஐ மட்டுமே எழுப்பும். இந்த நடத்தை ஒரு நிலையான பைத்தான் லிஸ்ட்டிலிருந்து வேறுபட்டது, அதை நீங்கள் பலமுறை இட்டரேட் செய்யலாம்.
ஒரு மேலும் வலுவான முறை: இட்டரபிளை இட்டரேட்டரிலிருந்து பிரித்தல்
பைத்தானின் உள்ளமைக்கப்பட்ட சேகரிப்புகளைப் போன்ற மீண்டும் பயன்படுத்தக்கூடிய இட்டரபிள்களை உருவாக்க, இரண்டு பாத்திரங்களையும் பிரிப்பதே சிறந்த நடைமுறையாகும். கொள்கலன் ஆப்ஜெக்ட் இட்டரபிளாக இருக்கும், மேலும் அதன் `__iter__` மெத்தட் அழைக்கப்படும் ஒவ்வொரு முறையும் அது ஒரு புதிய, புத்தம் புதிய இட்டரேட்டர் ஆப்ஜெக்டை உருவாக்கும்.
நமது எடுத்துக்காட்டை இரண்டு கிளாஸ்களாக மாற்றி அமைப்போம்: `Sentence` (இட்டரபிள்) மற்றும் `SentenceIterator` (இட்டரேட்டர்).
குறியீடு:
class SentenceIterator:
"""நிலை மற்றும் மதிப்புகளை உருவாக்குவதற்குப் பொறுப்பான இட்டரேட்டர்."""
def __init__(self, words):
self.words = words
self.index = 0
def __next__(self):
try:
word = self.words[self.index]
except IndexError:
raise StopIteration()
self.index += 1
return word
def __iter__(self):
# ஒரு இட்டரேட்டர் இட்டரபிளாகவும் இருக்க வேண்டும், தன்னைத்தானே திருப்பித் தர வேண்டும்.
return self
class Sentence:
"""இட்டரபிள் கொள்கலன் கிளாஸ்."""
def __init__(self, text):
# கொள்கலன் தரவை வைத்திருக்கிறது.
self.words = text.split()
def __iter__(self):
# ஒவ்வொரு முறையும் __iter__ அழைக்கப்படும்போது, அது ஒரு புதிய இட்டரேட்டர் ஆப்ஜெக்டை உருவாக்குகிறது.
return SentenceIterator(self.words)
# இதை எப்படி பயன்படுத்துவது
my_sentence = Sentence('This is a test')
print("முதல் இட்டரேஷன்:")
for word in my_sentence:
print(word)
print("\nஇரண்டாவது இட்டரேஷன்:")
for word in my_sentence:
print(word)
இப்போது, இது ஒரு லிஸ்ட் போலவே சரியாக வேலை செய்கிறது! ஒவ்வொரு முறையும் `for` லூப் தொடங்கும்போதும், அது `my_sentence.__iter__()` ஐ அழைக்கிறது, இது அதன் சொந்த நிலையுடன் (`self.index = 0`) ஒரு புத்தம் புதிய `SentenceIterator` இன்ஸ்டன்ஸை உருவாக்குகிறது. இது ஒரே `Sentence` ஆப்ஜெக்ட்டில் பல, சுயாதீனமான இட்டரேஷன்களை அனுமதிக்கிறது. இந்த முறை மிகவும் வலுவானது மற்றும் பைத்தானின் சொந்த சேகரிப்புகள் இப்படித்தான் செயல்படுத்தப்படுகின்றன.
எடுத்துக்காட்டு: எல்லையற்ற இட்டரேட்டர்கள்
இட்டரேட்டர்கள் வரையறுக்கப்பட்டதாக இருக்க வேண்டிய அவசியமில்லை. அவை தரவின் முடிவற்ற வரிசையைக் குறிக்கலாம். இங்குதான் அவற்றின் சோம்பேறி, ஒரு நேரத்தில் ஒன்று என்ற தன்மை ஒரு பெரிய நன்மையாகும். ஃபைபோனச்சி எண்களின் எல்லையற்ற வரிசைக்கு ஒரு இட்டரேட்டரை உருவாக்குவோம்.
குறியீடு:
class FibonacciIterator:
"""ஃபைபோனச்சி எண்களின் எல்லையற்ற வரிசையை உருவாக்குகிறது."""
def __init__(self):
self.a, self.b = 0, 1
def __iter__(self):
return self
def __next__(self):
result = self.a
self.a, self.b = self.b, self.a + self.b
return result
# இதை எப்படி பயன்படுத்துவது - எச்சரிக்கை: பிரேக் இல்லாமல் எல்லையற்ற லூப்!
fib_gen = FibonacciIterator()
for i, num in enumerate(fib_gen):
print(f"Fibonacci({i}): {num}")
if i >= 10: # நாம் ஒரு நிறுத்தும் நிபந்தனையை வழங்க வேண்டும்
break
இந்த இட்டரேட்டர் தானாக `StopIteration`-ஐ எழுப்பாது. லூப்பை முடிக்க ஒரு நிபந்தனையை (ஒரு `break` ஸ்டேட்மென்ட் போன்ற) வழங்குவது அழைக்கும் குறியீட்டின் பொறுப்பாகும். இந்த முறை தரவு ஸ்ட்ரீமிங், நிகழ்வு லூப்கள் மற்றும் எண் உருவகப்படுத்துதல்களில் பொதுவானது.
பைத்தான் சூழலமைப்பில் இட்டரேட்டர் புரோட்டோகால்
`__iter__` மற்றும் `__next__` ஐப் புரிந்துகொள்வது பைத்தானில் எல்லா இடங்களிலும் அவற்றின் செல்வாக்கைக் காண உங்களை அனுமதிக்கிறது. இது பைத்தானின் பல அம்சங்களை தடையின்றி ஒன்றாக வேலை செய்ய வைக்கும் ஒருங்கிணைக்கும் புரோட்டோகால் ஆகும்.
`for` லூப்கள் *உண்மையில்* எப்படி வேலை செய்கின்றன
நாம் இதை மறைமுகமாக விவாதித்தோம், ஆனால் அதை வெளிப்படையாகச் சொல்வோம். பைத்தான் இந்த வரியை சந்திக்கும்போது:
`for item in my_iterable:`
அது திரைக்குப் பின்னால் பின்வரும் படிகளைச் செய்கிறது:
- அது ஒரு இட்டரேட்டரைப் பெற `iter(my_iterable)` ஐ அழைக்கிறது. இது, `my_iterable.__iter__()` ஐ அழைக்கிறது. திரும்பப் பெறப்பட்ட ஆப்ஜெக்ட்டை `iterator_obj` என்று அழைப்போம்.
- அது ஒரு எல்லையற்ற `while True` லூப்பில் நுழைகிறது.
- லூப்பின் உள்ளே, அது `next(iterator_obj)` ஐ அழைக்கிறது, இது `iterator_obj.__next__()` ஐ அழைக்கிறது.
- `__next__` ஒரு மதிப்பைத் திருப்பினால், அது `item` மாறிக்கு ஒதுக்கப்பட்டு, `for` லூப் பிளாக்கின் உள்ளே உள்ள குறியீடு செயல்படுத்தப்படுகிறது.
- `__next__` ஒரு `StopIteration` விதிவிலக்கை எழுப்பினால், `for` லூப் இந்த விதிவிலக்கைப் பிடித்து அதன் உள் `while` லூப்பிலிருந்து வெளியேறுகிறது. இட்டரேஷன் முடிந்துவிட்டது.
காம்பிரிஹென்ஷன்கள் மற்றும் ஜெனரேட்டர் எக்ஸ்பிரஷன்கள்
லிஸ்ட், செட் மற்றும் அகராதி காம்பிரிஹென்ஷன்கள் அனைத்தும் இட்டரேட்டர் புரோட்டோகாலால் இயக்கப்படுகின்றன. நீங்கள் எழுதும்போது:
`squares = [x * x for x in range(10)]`
பைத்தான் `range(10)` ஆப்ஜெக்ட்டின் மீது திறம்பட ஒரு இட்டரேஷனைச் செய்கிறது, ஒவ்வொரு மதிப்பையும் பெற்று, லிஸ்ட்டை உருவாக்க `x * x` என்ற வெளிப்பாட்டைச் செயல்படுத்துகிறது. இது ஜெனரேட்டர் எக்ஸ்பிரஷன்களுக்கும் பொருந்தும், அவை சோம்பேறி இட்டரேஷனின் இன்னும் நேரடியான பயன்பாடாகும்:
`lazy_squares = (x * x for x in range(1000000))`
இது நினைவகத்தில் ஒரு மில்லியன் உருப்படிகள் கொண்ட லிஸ்ட்டை உருவாக்காது. இது ஒரு இட்டரேட்டரை (குறிப்பாக, ஒரு ஜெனரேட்டர் ஆப்ஜெக்ட்) உருவாக்குகிறது, அது நீங்கள் அதன் மீது இட்டரேட் செய்யும்போது, வர்க்கங்களை ஒவ்வொன்றாகக் கணக்கிடும்.
ஜெனரேட்டர்கள்: இட்டரேட்டர்களை உருவாக்குவதற்கான எளிய வழி
`__iter__` மற்றும் `__next__` உடன் ஒரு முழுமையான கிளாஸை உருவாக்குவது உங்களுக்கு அதிகபட்ச கட்டுப்பாட்டைக் கொடுத்தாலும், அது எளிய நிகழ்வுகளுக்கு விரிவாக இருக்கலாம். பைத்தான் இட்டரேட்டர்களை உருவாக்குவதற்கு மிகவும் சுருக்கமான ஒரு தொடரியலை வழங்குகிறது: ஜெனரேட்டர்கள்.
ஒரு ஜெனரேட்டர் என்பது `yield` என்ற முக்கிய சொல்லைப் பயன்படுத்தும் ஒரு செயல்பாடு ஆகும். நீங்கள் ஒரு ஜெனரேட்டர் செயல்பாட்டை அழைக்கும்போது, அது குறியீட்டை இயக்காது. அதற்கு பதிலாக, அது ஒரு ஜெனரேட்டர் ஆப்ஜெக்ட்டைத் திருப்பித் தருகிறது, இது ஒரு முழுமையான இட்டரேட்டர் ஆகும்.
நமது `CountUpTo` எடுத்துக்காட்டை ஒரு ஜெனரேட்டராக மீண்டும் எழுதுவோம்:
குறியீடு:
def count_up_to_generator(max_num):
"""1 முதல் max_num வரையிலான எண்களை வழங்கும் ஒரு ஜெனரேட்டர் செயல்பாடு."""
print("ஜெனரேட்டர் தொடங்கியது...")
current = 1
while current <= max_num:
yield current # இங்கே இடைநிறுத்தி ஒரு மதிப்பைத் திருப்பி அனுப்புகிறது
current += 1
print("ஜெனரேட்டர் முடிந்தது.")
# இதை எப்படி பயன்படுத்துவது
counter_gen = count_up_to_generator(3)
for number in counter_gen:
print(f"for லூப் பெற்றது: {number}")
அது எவ்வளவு எளிமையானது என்று பாருங்கள்! `yield` என்ற முக்கிய சொல் இங்கே மாயாஜாலம் செய்கிறது. `yield` சந்திக்கப்படும்போது, செயல்பாட்டின் நிலை முடக்கப்பட்டு, மதிப்பு அழைப்பாளருக்கு அனுப்பப்பட்டு, செயல்பாடு இடைநிறுத்தப்படுகிறது. அடுத்த முறை ஜெனரேட்டர் ஆப்ஜெக்ட்டில் `__next__` அழைக்கப்படும்போது, செயல்பாடு அது விட்ட இடத்திலிருந்தே மீண்டும் தொடங்குகிறது, அது மற்றொரு `yield`-ஐ அடையும் வரை அல்லது செயல்பாடு முடியும் வரை. செயல்பாடு முடிந்ததும், உங்களுக்காக ஒரு `StopIteration` தானாகவே எழுப்பப்படுகிறது.
திரைக்குப் பின்னால், பைத்தான் `__iter__` மற்றும் `__next__` மெத்தட்களுடன் ஒரு ஆப்ஜெக்டை தானாகவே உருவாக்கியுள்ளது. ஜெனரேட்டர்கள் பெரும்பாலும் நடைமுறைத் தேர்வாக இருந்தாலும், அடிப்படைக் புரோட்டோகாலைப் புரிந்துகொள்வது பிழைதிருத்தம், சிக்கலான அமைப்புகளை வடிவமைத்தல் மற்றும் பைத்தானின் மைய இயக்கவியல் எவ்வாறு செயல்படுகிறது என்பதைப் பாராட்டுவதற்கு அவசியமானது.
சிறந்த நடைமுறைகள் மற்றும் பொதுவான தவறுகள்
இட்டரேட்டர் புரோட்டோகாலைச் செயல்படுத்தும்போது, பொதுவான பிழைகளைத் தவிர்க்க இந்த வழிகாட்டுதல்களை மனதில் கொள்ளுங்கள்.
சிறந்த நடைமுறைகள்
- இட்டரபிள் மற்றும் இட்டரேட்டரை பிரிக்கவும்: பல முறை பயணிக்க வேண்டிய எந்தவொரு கொள்கலன் ஆப்ஜெக்டிற்கும், எப்போதும் இட்டரேட்டரை ஒரு தனி கிளாஸில் செயல்படுத்தவும். கொள்கலனின் `__iter__` மெத்தட் ஒவ்வொரு முறையும் இட்டரேட்டர் கிளாஸின் ஒரு புதிய இன்ஸ்டன்ஸைத் திருப்பித் தர வேண்டும்.
- எப்போதும் `StopIteration`-ஐ எழுப்பவும்: `__next__` மெத்தட் முடிவை சமிக்ஞை செய்ய நம்பத்தகுந்த வகையில் `StopIteration`-ஐ எழுப்ப வேண்டும். இதை மறந்துவிடுவது எல்லையற்ற லூப்களுக்கு வழிவகுக்கும்.
- இட்டரேட்டர்கள் இட்டரபிளாக இருக்க வேண்டும்: ஒரு இட்டரேட்டரின் `__iter__` மெத்தட் எப்போதும் `self`-ஐ திருப்பித் தர வேண்டும். இது ஒரு இட்டரேட்டரை இட்டரபிள் எதிர்பார்க்கப்படும் எங்கும் பயன்படுத்த அனுமதிக்கிறது.
- எளிமைக்காக ஜெனரேட்டர்களை விரும்பவும்: உங்கள் இட்டரேட்டர் தர்க்கம் நேரடியானது மற்றும் ஒரு ஒற்றைச் செயல்பாடாக வெளிப்படுத்த முடிந்தால், ஒரு ஜெனரேட்டர் கிட்டத்தட்ட எப்போதும் சுத்தமாகவும் படிக்க எளிதாகவும் இருக்கும். நீங்கள் இட்டரேட்டர் ஆப்ஜெக்ட்டுடனேயே மேலும் சிக்கலான நிலை அல்லது மெத்தட்களை இணைக்க வேண்டியிருக்கும்போது ஒரு முழு இட்டரேட்டர் கிளாஸைப் பயன்படுத்தவும்.
பொதுவான தவறுகள்
- தீர்ந்துவிடக்கூடிய இட்டரேட்டர் சிக்கல்: விவாதித்தபடி, ஒரு ஆப்ஜெக்ட் அதன் சொந்த இட்டரேட்டராக இருக்கும்போது, அதை ஒரு முறை மட்டுமே பயன்படுத்த முடியும் என்பதை அறிந்து கொள்ளுங்கள். நீங்கள் பலமுறை இட்டரேட் செய்ய வேண்டுமானால், நீங்கள் ஒரு புதிய இன்ஸ்டன்ஸை உருவாக்க வேண்டும் அல்லது பிரிக்கப்பட்ட இட்டரபிள்/இட்டரேட்டர் முறையைப் பயன்படுத்த வேண்டும்.
- நிலையை மறந்துவிடுதல்: `__next__` மெத்தட் இட்டரேட்டரின் உள் நிலையை மாற்றியமைக்க வேண்டும் (எ.கா., ஒரு குறியீட்டை அதிகரிப்பது அல்லது ஒரு சுட்டியை நகர்த்துவது). நிலை புதுப்பிக்கப்படாவிட்டால், `__next__` மீண்டும் மீண்டும் அதே மதிப்பைத் திருப்பித் தரும், இது ஒரு எல்லையற்ற லூப்பை ஏற்படுத்தக்கூடும்.
- இட்டரேட் செய்யும்போது ஒரு சேகரிப்பை மாற்றுதல்: ஒரு சேகரிப்பின் மீது இட்டரேட் செய்யும்போது அதை மாற்றுவது (எ.கா., அதன் மீது இட்டரேட் செய்யும் `for` லூப்பிற்குள் ஒரு லிஸ்ட்டிலிருந்து உருப்படிகளை அகற்றுவது) கணிக்க முடியாத நடத்தைக்கு வழிவகுக்கும், அதாவது உருப்படிகளைத் தவிர்ப்பது அல்லது எதிர்பாராத பிழைகளை எழுப்புவது. நீங்கள் அசலை மாற்றியமைக்க வேண்டுமானால், சேகரிப்பின் ஒரு நகலின் மீது இட்டரேட் செய்வது பொதுவாக பாதுகாப்பானது.
முடிவுரை
இட்டரேட்டர் புரோட்டோகால், அதன் எளிய `__iter__` மற்றும் `__next__` மெத்தட்களுடன், பைத்தானில் இட்டரேஷனின் அடித்தளமாகும். இது மொழியின் வடிவமைப்பு தத்துவத்திற்கு ஒரு சான்றாகும்: சக்திவாய்ந்த மற்றும் சிக்கலான நடத்தைகளை செயல்படுத்தும் எளிய, சீரான இடைமுகங்களுக்கு சாதகமாக இருப்பது. வரிசைமுறை தரவு அணுகலுக்கான ஒரு உலகளாவிய ஒப்பந்தத்தை வழங்குவதன் மூலம், இந்த புரோட்டோகால் `for` லூப்கள், காம்பிரிஹென்ஷன்கள் மற்றும் எண்ணற்ற பிற கருவிகளை அதன் மொழியைப் பேசத் தேர்ந்தெடுக்கும் எந்தவொரு ஆப்ஜெக்ட்டுடனும் தடையின்றி வேலை செய்ய அனுமதிக்கிறது.
இந்த புரோட்டோகாலில் தேர்ச்சி பெறுவதன் மூலம், பைத்தான் சூழலமைப்பில் முதல்-தர குடிமக்களாக இருக்கும் உங்கள் சொந்த வரிசை போன்ற ஆப்ஜெக்ட்களை உருவாக்கும் திறனை நீங்கள் திறந்துள்ளீர்கள். நீங்கள் இப்போது தரவை சோம்பேறித்தனமாக செயலாக்குவதன் மூலம் அதிக நினைவக-திறனுள்ள, நிலையான பைத்தான் தொடரியலுடன் சுத்தமாக ஒருங்கிணைப்பதன் மூலம் அதிக உள்ளுணர்வுள்ள, மற்றும் இறுதியில், அதிக சக்திவாய்ந்த கிளாஸ்களை எழுதலாம். அடுத்த முறை நீங்கள் ஒரு `for` லூப்பை எழுதும்போது, மேற்பரப்பிற்கு அடியில் நடக்கும் `__iter__` மற்றும் `__next__`-இன் நேர்த்தியான நடனத்தைப் பாராட்ட ஒரு கணம் எடுத்துக் கொள்ளுங்கள்.